home *** CD-ROM | disk | FTP | other *** search
- {$X+}
- { XBFORMAT.PAS - Support Xbase file structures
-
- Xphiles(tm) source code
- Copyright (c) 1995 - 1996 by Interface Technologies
- All Rights Reserved Worldwide
-
- }
- unit XbFormat;
-
- interface
-
- uses Classes, XbConst, SysUtils, Dialogs;
-
- const
-
- DBFFieldTypes = [ 'B', 'C', 'D', 'F', 'G', 'I', 'L', 'M', 'N', 'P', 'T',
- 'V', 'Y' ];
- { Index file constants }
- _NTX_MAX_KEY = 255; { Maximum length of NTX key expression }
- _NDX_MAX_KEY = 487; { Maximum length of NDX key expression }
- _CDX_BLK_SIZE = 512; { Size of CDX blocks }
-
- { MDX File constants }
- MDX_SIGNATURE = 2; { type code for .mdx file }
-
- { MDX_PAGELEN = 512; { length in bytes of a page }
-
- MDX_DESCENDING = $08; { index is descending }
- MDX_TAGFIELD = $10; { shows tag is a field in file }
- MDX_UNIQUE = $40; { index excludes duplicate keys }
-
- { MDX_BLOCKHEADLEN = 8; { header length of index body block }
-
- MDX_FLAG_DESCENDING = $0008;
- MDX_FLAG_FIELDTAG = $0010;
- MDX_FLAG_UNIQUE = $0040;
-
- { HiPer SIx / NSX file constants }
- _NSX_PAGE_LEN = 1024; { Size of pages }
- _NSX_MIDKEY_CHECK = 10; { Insert threshhold for mid-key check }
- _NSX_TAG_MAX = 11; { Max length of tag name }
- _NSX_MAX_TAGS = 50; { Max number of tags per file }
- _NSX_MAX_KEY = 256; { Max key expression length }
-
- { NSX RYO masks }
- _NSX_PARTIAL = $0100; { Partial index }
- _NSX_TEMPLATE = $0200; { 0x0200 }
- _NSX_CHANGES_ONLY = $0400; { Only record changes only }
- _NSX_NO_UPDATE = $0800; { Don't update when records change }
- _NSX_SHADOW = $1000; { 0x1000 }
-
- { FRM file constants }
- _FRM_EXP_COUNT = 55; { Max # of expressions }
- _FRM_MAX_EXPR = 1440; { Total bytes for form expressions }
- _FRM_MAX_FIELDS = 25; { Max # of columns in a form }
-
- { LBL file constants }
- _LBL_COUNT = 15; { 0 .. 15, label line entries }
- _LBL_SIZE = 59; { 0 .. 59, 60 chars for contents }
-
- { DBF signature bytes }
- _DBF_FOXBASE = $02; { FoxBase, no memo }
- _DBF_NO_MEMO = $03; { dBASE III+ }
- _DBF_ENCRYPT = $06; { Apollo encrypted, no memo }
- _DBF_VFP = $30; { Visual FoxPro }
- _DBF_DB4_SQL = $43; { dBASE IV SQL table, no memo }
- _DBF_DB4_SQLSYS = $63; { dBASE IV SQL system file, no memo }
- _DBF_DBT_MEMO = $83; { CA-Clipper/dBASE III+ .DBT memo }
- _DBF_DBT_ENCRYPT = $86; { Apollo encrypted, no memo }
- _DBF_DB4_MEMO = $8B; { dBASE IV .DBT memo }
- _DBF_DB4_SQLMEMO = $CB; { dBASE IV SQL table, memo }
- _DBF_SMT_MEMO = $E5; { HiPer SIx with memo }
- _DBF_SMT_ENCRYPT = $E6; { HiPer SIx with memo, encrypted }
- _DBF_FPT_MEMO = $F5; { FoxPro .FPT memo }
- _DBF_FPT_ENCRYPT = $F6; { Apollo encrypted, FoxPro memo }
- _DBF_FOX_MEMO = $FB; { FoxBASE memo }
-
- _DBT4_VERSION = $0102; { dBASE IV v1.0 and 1.5 }
-
- type
-
- xbMemoType = ( xbDB3, xbDB4, xbFPT, xbSMT );
-
- EXbFormatError = class( Exception );
-
- DBFHeaderRec = packed record { DBF File header record, 32 bytes}
- iSignature : byte; { Type of memo file used (see constants) }
- iYear : byte; { Last update (YMD), Year part }
- iMonth : byte; { Last update (YMD), Month part }
- iDay : byte; { Last update (YMD), Day part }
- lRecords : longint; { # of records in the file }
- wDataOffset : word; { Data offset (Least significant byte first) }
- wRecLen : word; { Length of a record }
- wFiller : word; { 2 unused bytes (should be 0s) }
- bIncomplete : boolean; { Incomplete dBASE IV Transaction? }
- bEncrypted : boolean; { dBASE IV Encryption flag }
- sMultiuser : string[11]; { 12 bytes for multi-user processing }
- iFlags : boolean; { Table flags:
- $01 = file has production .MDX / .CDX
- $02 = file has memos (VFP)
- $04 = file is a Database (.DBC) - (VFP) }
- iLanguage : byte; { Language driver ID, code page }
- wFiller2 : word; { 2 unused bytes (should be 0s) }
- end; { DBFHeaderRec }
-
- DBFieldEnd = packed record { dBASE IV, FoxPro field modifications }
- iFlags : byte; { VFP Field Flags:
- $01 System Column (not visible to user)
- $02 Column can store null values
- $04 Binary column (Char or Memo only) }
- cFiller1 : byte; { 1 unused bytes }
- iWorkArea : byte; { Work area }
- sFiller2 : string[9]; { 10 unused bytes }
- bProduction : boolean; { Production .MDX field flag }
- end; { DBFieldEnd }
-
- DBFieldRec = packed record { DBF File field header record, 32 bytes }
- szName : array [ 0..10 ] of char; { Field name }
- case cFieldType : char of { Field Type }
- 'C' :
- ( lPlacement : longint; { Field placement (VFP) }
- wCharLen : word; { Length of character field }
- recInfo : DBFieldEnd ); { For Visual dBASE, VFP }
- 'B', 'D', 'T', 'F', 'G', 'L', 'M', 'N', 'Y', 'I', 'P':
- ( lPlacement2 : longint; { Field placement (VFP) }
- iLength : byte; { Length of field }
- iDecimal : byte; { Decimals of field }
- recInfo1 : DBFieldEnd ); { For Visual dBASE, VFP }
-
- end; { DBFieldRec }
-
- DBT3HeaderRec = packed record { dBASE III+/CA-Clipper memo file header }
- lBlocks : longint; { # of blocks used, including header }
- szFiller : array [ 0..507 ] of char; { 508 unused characters }
- end; { DBT3HeaderRec }
-
- DBT4HeaderRec = packed record { dBASE IV and up header }
- lNextBlock : longint; { Next free block to be used }
- lCurBlockSz : longint; { Size of current block (0 in v1.0 - 1.5 ) }
- szDBFName : array [ 0..8 ] of char; { Associated .DBF file name }
- cFiller1 : byte; { 1 Reserved byte }
- wVersion : word; { $102 in v1.0 - 1.5 }
- wBlockSize : word; { Block size being used, in K }
- bEncrypted : boolean; { Is file encrypted? }
- cFiller2 : char; { 1 unused char }
- end; { DBT4HeaderRec }
-
- SMTHeaderRec = packed record { HiPer SIx memo file header }
- lNextBlock : longint; { Next free block to be used }
- lBlockSize : longint; { Block size being used, in bytes }
- sWasted : array[ 0..503 ] of char; { 504 Unused characters }
- end; { SMTHeaderRec }
-
- FPTHeaderRec = packed record { FoxPro memo file header }
- lNextBlock : longint; { Next free block to be used, byte reversed }
- lBlockSize : longint; { Block size being used, byte reversed }
- sWasted : array[ 0..503 ] of char; { 504 Unused characters }
- end; { FPTHeaderRec }
-
- FPTBlockRec = packed record { FoxPro memo file block }
- lDataType : longint; { Type of data in block }
- lLength : longint; { Length of memo entry, in bytes }
- pBuffer : pointer;
- { Memo text (or data), where n equals the length of the memo entry plus
- the eight byte record header. The pointer is not really part of the
- structure -- it has to be allocated and assigned to the data immediately
- following lLength }
- end; { FPTBlockRec }
-
- NTXHeaderRec = packed record { NTX File header, 278 bytes }
- wSign : word; { Value 03 for Clipper file }
- wVersion : word; { Version of Clipper indexing system }
- lRootPage : longint; { Offset to the first index page }
- lNextPage : longint; { Offset to first unused page }
- wItemSize : word; { Size of the index key + two longs }
- wKeySize : word; { Size of the index key value }
- wKeyDec : word; { Decimal places for numeric index }
- wMaxItem : word; { Maximum # of keys per page }
- wHalfPage : word; { Half of MaxItem }
- { Index key expression }
- szExpression : array[ 0.._NTX_MAX_KEY ] of char;
- wUnique : word; { Unique ON=1 OFF=0 }
- end; { NTXHeaderRec }
-
- NDXHeaderRec = packed record { NDX File header, 512 bytes }
- lStartKeyPage : longint; { Record # of root page }
- lTotalPages : longint; { # of 512 byte pages in file }
- lFiller1 : longint; { Four unused bytes }
- wKeySize : word; { Size of the index key }
- wMaxItem : word; { Maximum # of keys per page }
- wKeyType : word; { 01 = Numeric, 00 = char }
- wSizeKeyRec : word; { Size of an NDX_KEY_REC }
- cFiller2 : char; { one byte of unused space }
- bUnique : boolean; { Unique ON=1, OFF=0 }
- { Index key expression }
- szExpression : array[ 0.._NDX_MAX_KEY ] of char;
- end; { NTXHeaderRec }
-
- FRMFieldRec = packed record { FRM field header }
- iWidth : shortint; { Print width of field }
- sFiller1 : string[ 2 ]; { 3 bytes of filler }
- cTotal : char; { Should numbers be totaled? }
- iDec : shortint; { # of Decimal places }
- iExpContents : shortint; { Exp # for field's contents }
- iExpHeader : shortint; { Exp # for field's header }
- end; { FRMFieldRec }
-
- FRMHeaderRec = packed record { FRM file header }
- iSign1 : shortint; { value 02 indicates a FRM file }
- iExpEnd : shortint; { Next free char in ExpArea }
- { Array of exp lengths }
- aiExpLength : array [ 1.._FRM_EXP_COUNT ] of shortint;
- { Indices into ExpArea for start of exp }
- aiExpIndex : array [ 1.._FRM_EXP_COUNT] of shortint;
- { Container for expressions indexed by
- above arrays }
- pExpArea : array [ 0.._FRM_MAX_EXPR - 1 ] of char;
- { Array of FRMFields. First is unused. }
- aFields : array [ 1.._FRM_MAX_FIELDS ] of FRMFieldRec;
- iTitle : shortint; { Exp number of title string }
- iGrpOn : shortint; { GROUP ON exp number }
- iSubOn : shortint; { SUB GROUP ON exp number }
- iGrpHead : shortint; { Exp # of GROUP ON heading }
- iSubHead : shortint; { Exp # of SUB GROUP ON heading }
- iPageWidth : shortint; { Width of page }
- iLinesPerPage : shortint; { # of lines per page }
- iLeftMargin : shortint; { Left margin }
- iRightMargin : shortint; { Right margin }
- iColCount : shortint; { # of columns }
- cDoubleSpace : char; { Y if doublespaced, N if not }
- cSummary : char; { Y if summary, N if not }
- cEject : char; { Y if eject page after group, or N }
- iPlusBytes : byte; { bit 0=1: EJECT BEFORE PRINT }
- { bit 1=1: EJECT AFTER PRINT }
- { bit 2=1: PLAIN report }
- iSign2 : shortint; { value 02 }
- end; { FRMHeaderRec }
-
- LBLFieldRec = array[ 0.._LBL_SIZE ] of char;
-
- LBLHeaderRec = packed record { Label file header }
- iSignature : byte; { Signature byte - should be 1 }
- { Description of label file }
- szRemarks : array [ 0..59 ] of char;
- iHeight : shortint; { Height of label }
- iWidth : shortint; { Width of label }
- iLeftMargin : shortint; { Left margin }
- iLabelLine : shortint; { Length of label line }
- iLabelSpace : shortint; { Space between labels }
- iLabelsAcross : shortint; { # of labels across }
- aInfo : array [ 0.._LBL_COUNT ] of LBLFieldRec;
- iSignature2 : byte; { Same as iSignature }
- end; { LBLHeaderRec }
-
- MEMVarRec = packed record { Memory variable file structure }
- { Variable name }
- szVarName : array [ 0..10 ] of char;
- cType : char; { Type of variable }
- lFiller1 : longint; { 4 unused bytes }
- iLen : byte; { Length of data for variable }
- iDec : byte; { Decimal precision }
- sFiller2 : string[ 14 ];{ Second filler region }
- end; { MEMVarRec }
-
- CDXNodeHeadRec = packed record { CDX file node header }
- iNodeAttribute : shortint; { 0: Index, 1: Root, 2: Leaf }
- iNKeys : shortint; { Number of keys in node }
- lLeftNode : longint; { Offset of left sibling (-1, not present) }
- lRightNode : longint; { Offset of right sibling (-1, not present) }
- end; { CDXNodeHeadRec }
-
- { dBASE MDX date stamp }
-
- MDXDate = packed record
- iYear : byte;
- iMonth : byte;
- iDay : byte;
- end; { MDXDate }
-
- { first 48 bytes of an .mdx file }
-
- MDXHeader = packed record
- iFileType : byte; { error if not MDXTYPE }
- LastIndex : MDXDate; { last reindex date }
- { root name of associated .dbf }
- szRootDBF : array [0..15 ] of char;
- iBlockSize : integer; { SET BLOCKSIZE value, minimum = 2 }
- iBlockBytes : smallint; { block size in bytes }
- bProduction : boolean; { True if production .mdx, else False }
- sFiller : string[2]; { 3 unused bytes }
- iIndexCount : smallint; { number of indexes in the file }
- iFiller : smallint; { 2 unused bytes }
- lEndFilePage : longint; { unsigned: page number of end of file }
- lNextFreePage : longint; { unsigned: page number of next free block }
- lFreePages : longint; { unsigned: pages in next free block }
- Created : MDXDate; { file creation date }
- cFiller : byte; { 1 unused byte }
- end; { MDXHeader }
-
- { An MDX index tag description }
-
- MDXTagDesc = packed record
- lIndHeaderPage : longint; { page number of index header }
- { MDX tag name, null-terminated }
- szTagName : array [ 0..10 ] of char;
- iTagIsField : byte; { 10 if the tag is a field, else 0 }
- { usage counters }
- aCounters : array [ 0..3 ] of byte;
- iFiller : byte; { 1 unused byte filler, always 02 }
- cKeyType : char; { C, D, or N for key type }
- sFiller : string[11]; { 12 unused bytes }
- end; { MDXTagDesc }
-
- { header of an index }
-
- MDXTagHeader = packed record
- lRootPage : longint; { Unsigned: page number of index root }
- lPagesUsed : longint; { Unsigned: pages used by the index }
- iFlags : byte; { Index status flags: see MDX_FLAG constants }
- cKeyType : char; { C, D or N for key type }
- bSQL : boolean; { True if optimized for SQL, else False }
- cFiller : byte; { 1 unused character }
- wKeyLength : word; { length of key in bytes }
- lMaxNodes : longint; { unsigned: maximum nodes in a block }
- wRecLen : word; { length of an index record in bytes }
- wChanges : word; { change counter for optimization }
- cFiller2 : byte; { 1 unused character }
- iUniqueFlag : smallint; { $40 if UNIQUE, else 0 }
- { The index key expression }
- szKeyExp : array [ 0..100 ] of char;
- end; { MDXTagHeader }
-
- CDXNodeInfoRec = packed record { CDX file node information }
- iFreeSpace : shortint; { # of bytes available in node }
- lRecNumMask : word; { Record number mask }
- iDupByteCnt : byte; { Duplicate byte mask count }
- iTrailByteCnt : byte; { Trailing byte mask count }
- iRecNumLen : byte; { # of bits used for record number }
- iDupCntLen : byte; { # of bits used for duplicate count }
- iTrailCntLen : byte; { # of bits used for trailing blank count }
- iInfoLen : byte; { # of bytes used for record number }
- end; { CDXNodeInfoRec }
-
- CDXTagHeadRec = packed record { CDX Tag header }
- lRoot : longint; { Offset of root block }
- lFree_list : longint; { Start of the free list (-1 if none) }
- lLength : longint; { Length of file (non-compact only) }
- iKeyLen : shortint; { Key Length }
- ucTypeCode : byte; { 0x01: Unique; 0x02, 0x04: RYO; 0x08:
- Conditional 0x20: Compact; 0x60: Compound }
- end; { CDXTagHeadRec }
-
- CDXTagRec = packed record { CDX Tag entry }
- iKeyOn : shortint; { Current key # (0 - based) }
- { Current key data (10 bytes for tag name
- + null) }
- szKey : array [ 0..10 ] of char;
- pCurPos : pointer; { Pointer to current position in data }
- iKeyLen : shortint; { Key length }
- sHeader : CDXNodeHeadRec; { Node header }
- sNodeInfo : CDXNodeInfoRec; { Node info }
- caData : array [ 0.._CDX_BLK_SIZE - ( sizeof( CDXNodeHeadRec )
- + sizeof( CDXNodeInfoRec ) ) ] of char; { Data }
- end; { CDXTagRec }
-
- TDBField = class
- private
- protected
- sName : string;
- cType : char;
- iLength : smallint;
- iDecimal : smallint;
-
- function GetName : string;
- procedure SetName( sNew : string );
- function GetType : char;
- procedure SetType( cNew : char );
- function GetLength : smallint;
- procedure SetLength( iNew : smallint );
- function GetDecimal : smallint;
- procedure SetDecimal( iNew : smallint );
- public
- property FieldName : string read GetName write SetName;
- property FieldType : char read GetType write SetType;
- property FieldLength : smallint read GetLength write SetLength;
- property FieldDecimal : smallint read GetDecimal write SetDecimal;
- function TypeWord : string;
- constructor Create( { Create the field entry }
- sFieldName : string; { Name of the field }
- cFieldType : char; { Character type code for the field }
- iFieldLength : smallint; { Length of the field }
- iFieldDecimal : smallint { Decimal precision for numeric fields }
- );
- function IsMemo : boolean; { Is field stored in memo file? }
- function Header : DBFieldRec;
- end; { TDBField }
-
- TDBStruct = Class( TList )
- private
- protected
- iBlockSize : smallint; { Memo file block size }
- function GetField(
- Index : smallint { Index of entry to get }
- ) : TDBField; { Returns the relevant TDBField }
- procedure PutField(
- Index : smallint; { Index of entry to put }
- oField : TDBField ); { TDBField object to put }
- function MakeMemoHeader( { Write a memo header structure to file }
- sFile : string; { Name of memo file }
- const Header; { Header structure to write }
- iSize : longint { Size of header structure }
- ) : boolean; { True if successful }
- function MakeDBT3( { Create dBASE III+/CA-Clipper memo file }
- sFile : string { Name of DBF file }
- ) : boolean;
- function MakeDBT4( { Create dBASE IV and up memo file }
- sFile : string { Name of DBF file }
- ) : boolean;
- function MakeSMT( { Create a HiPer SIx memo file }
- sFile : string { Name of DBF file }
- ) : boolean;
- function MakeFPT( { Create a FoxPro memo file }
- sFile : string { Name of DBF file }
- ) : boolean;
- function MakeMemo( { Create the memo file for the DBF }
- sFile : string { Name of DBF file }
- ) : boolean;
- function GetBlockSize : smallint;
- procedure SetBlockSize( { Set the block size }
- iNew : smallint );
- public
- bEncrypt : boolean; { Encrypt the file? }
- sDriver : string; { Name of the driver to use }
- procedure Free;
- procedure Eval( { Iterate through structure }
- cbProc : xbBlockProc { Data type for "code block" }
- );
- function Make( { Create the DBF file }
- sFile : string { DBF file name }
- ) : boolean; { True if successful }
- property BlockSize : smallint read GetBlockSize write SetBlockSize;
- function TableType : xbMemoType; { Type of Driver for Table }
- function Signature : byte; { Signature byte for DBF }
- function HasMemo : boolean; { Is there a memo field in the DBF? }
- function DataOffset : smallint; { Position of first record in file }
- function RecordLength : smallint; { # of bytes per record }
- property Fields[ Index : smallint ] : TDBField read GetField
- write PutField;
- constructor Create;
- end; { TDBStruct class }
-
- function DBFieldCount( { # of fields in data file }
- recDBF : DBFHeaderRec { Database file header }
- ) : smallint;
-
- function dbCreateStruct( { Convert array of const to DBStruct }
- aStruct : array of const { Field structure information:
- 4 array elements per field:
- 1. Field name (string)
- 2. Field type (char)
- 3. Field length (smallint)
- 4. Field decimal (smallint) }
- ) : TDBStruct; { Use TDBStruct.Free when done! }
-
- function DBStructRead( { Read the structure from a DBF file }
- sFile : string
- ) : TDBStruct;
-
- function DBFileType( { DBF File Type }
- iSignature : byte { Signature byte }
- ) : string;
-
- procedure ShowDBF( { Show structure of an DBF file }
- sFile : string ); { Name of DBF file }
-
- procedure ShowDBT3( { Show structure of a DBT3 file }
- sFile : string ); { Name of DBT file }
-
- procedure ShowDBT4( { Show structure of a DBT4 file }
- sFile : string ); { Name of DBT file }
-
- procedure ShowSMT( { Show structure of an SMT file }
- sFile : string ); { Name of SMT file }
-
- procedure ShowFPT( { Show structure of an FPT file }
- sFile : string ); { Name of FPT file }
-
- {$IFNDEF XP_NO_NATIVE_DBCREATE}
- function dbCreate( { Create a data file }
- sDataFile : string; { Name of data file to create }
- oStruct : TDBStruct; { Database structure object }
- sDriver : string; { Name of data driver to use for creation }
- bEncrypt : boolean { Encrypt the file? }
- ) : boolean;
- {$ENDIF}
-
- function dbHeaderRead( { Read in a header from a file }
- sFile : string; { Name of file to read }
- var Header; { Header structure to read }
- iSize : smallint { Size of header structure }
- ) : boolean; { True if read successfully }
-
- implementation
-
- { Miscellaneous utility functions culled from other files }
- function AllTrim( sTrim : string ) : string;
- const
- WhiteSpace = [ #9, ' ', #0, #255 ];
- var
- iFront,
- iBack : integer;
- begin
- iFront := 1;
- iBack := Length( sTrim );
- while ( iFront < iBack ) and ( sTrim[ iFront ] in WhiteSpace ) do
- Inc( iFront );
- while ( iBack > iFront ) and ( sTrim[ iBack ] in WhiteSpace ) do
- Dec( iBack );
- Result := Copy( sTrim, iFront, iBack - iFront + 1 );
- end; { AllTrim() }
-
- function FCreate( { Create/overwrite a file }
- sFile : string; { Name of file to create }
- wMode : word { File creation mode }
- ) : Integer; { See FileCreate(), Rewrite(), _lcreate() }
- var
- szFile : array [ 0..255 ] of char;
- begin
- StrPCopy( szFile, sFile );
- Result := _lcreat( szFile, wMode );
- end; { FCreate() }
-
- function StringInSet( { Is every character of string in set? }
- sInput : string; { String to test every character of }
- cSet : CharSet { Set of all potential characters }
- ) : boolean; { Return True if all chars in set }
- var
- iPos,
- iLen : integer;
- begin
- Result := True;
- iPos := 1;
- iLen := Length( sInput );
- while ( Result ) and ( iPos <= iLen ) do begin
- Result := sInput[ iPos ] in cSet;
- Inc( iPos, 1 );
- end; { while }
- end; { StringInSet() }
-
- function IsSymbol( { Is this a valid symbol name? }
- sInput : string { String to test }
- ) : boolean;
- begin
- Result := ( sInput[ 1 ] in [ '_', 'A'..'Z' ] ) and
- ( StringInSet( sInput, [ '0'..'9', '_', 'A'..'Z', 'a'..'z' ] ) );
- end; { IsSymbol() }
-
- function RAny( sCharSet, sSource : string; iStart : Integer ) : Integer;
- var
- iPos : Integer;
-
- begin
- if iStart > 0 then
- iPos := iStart
- else
- iPos := Length( sSource );
- while ( iPos > 0 ) and ( Pos( sSource[ iPos ], sCharSet ) = 0 ) do
- Dec( iPos );
- Result := iPos;
- end; { RAny() }
-
- function ExtractFileFirst( sFile : string ) : string;
- var
- iStart, iStop : Integer;
-
- begin
- iStart := RAny( ':\', sFile, 0 );
- iStop := RAny( '.', sFile, 0 );
- if ( iStop = 0 ) or ( iStart > iStop ) then iStop := Length( sFile );
- Result := Copy( sFile, iStart + 1, iStop - iStart - 1 );
- end; { ExtractFileFirst() }
-
- { End miscellaneous utility functions }
-
- function ReverseBytes( { Swap silly FoxPro byte-reversed longints }
- lVal : longint { Value to swap }
- ) : longint;
- var
- pVal : array [ 0..3 ] of byte;
- iTemp : byte;
- begin
-
- Move( lVal, pVal, SizeOf( lVal ) );
-
- iTemp := pVal[ 0 ];
- pVal[ 0 ] := pVal[ 3 ];
- pVal[ 3 ] := iTemp;
- iTemp := pVal[ 1 ];
- pVal[ 1 ] := pVal[ 2 ];
- pVal[ 2 ] := iTemp;
-
- Move( pVal, lVal, SizeOf( lVal ) );
- Result := lVal;
- end; { ReverseBytes() }
-
- function dbHeaderRead( { Read in a header from a file }
- sFile : string; { Name of file to read }
- var Header; { Header structure to read }
- iSize : smallint { Size of header structure }
- ) : boolean; { True if read successfully }
- var
- iHandle : smallint;
- begin
- Result := False;
- try
- iHandle := FileOpen( sFile, FO_READ );
- if iHandle > -1 then
- if FileRead( iHandle, Header, iSize ) = iSize then
- Result := True;
- finally
- FileClose( iHandle );
- end; { try .. finally }
- end; { dbHeaderRead() }
-
- function TDBField.GetName : string;
- begin
- Result := sName;
- end; { TDBField.GetName }
-
- procedure TDBField.SetName( sNew : string );
- begin
- sNew := UpperCase( AllTrim( sNew ) );
- if IsSymbol( sNew ) then
- sName := sNew
- else
- Raise EXbFormatError.Create( 'Bad field name: "' + sNew + '"' );
- end; { TDBField.SetName() }
-
- function TDBField.GetType : char;
- begin
- Result := cType;
- end; { TDBField.GetType }
-
- procedure TDBField.SetType( cNew : char );
- begin
- cNew := UpCase( cNew );
- if cNew in DBFFieldTypes then begin
- cType := cNew;
- if not ( cType in [ 'F', 'N' ] ) then
- iDecimal := 0;
- case cNew of
- 'D' : iLength := 8;
- 'L' : iLength := 1;
- 'B',
- 'G',
- 'M' : iLength := 10;
- end; { case }
- end { valid type designator }
- else
- Raise EXbFormatError.Create( 'Bad field type: "' + cNew + '"' );
- end; { TDBField.SetType() }
-
- function TDBField.GetLength : smallint;
- begin
- Result := iLength;
- end; { TDBField.GetLength }
-
- procedure TDBField.SetLength( iNew : smallint );
- var
- iLow,
- iHigh : smallint;
- begin
- iLow := 1;
- case cType of { Q: verify appropriate type lengths }
- 'C' : iHigh := 32733;
- 'D' :
- begin
- iLow := 8;
- iHigh := 8;
- end;
- 'F' : iHigh := 20; { Q: Is this correct? }
- 'L' : iHigh := 1;
- 'B',
- 'G',
- 'P',
- 'M' :
- begin
- iLow := 10;
- iHigh := 10;
- end;
- 'N' : iHigh := 19;
- 'I' : iHigh := 4;
- end; { case }
- if ( iLow <= iNew ) and ( iNew <= iHigh ) then
- iLength := iNew
- else
- Raise EXbFormatError.Create(
- AllTrim( IntToStr( iNew ) ) + ' is a bad field length for a '
- + TypeWord + ' field' );
- end; { TDBField.SetLength() }
-
- function TDBField.GetDecimal : smallint;
- begin
- Result := iDecimal;
- end; { TDBField.GetDecimal }
-
- procedure TDBField.SetDecimal( iNew : smallint );
- begin
- if ( iNew = 0 ) or ( ( cType in [ 'N', 'F' ] ) and ( iNew > 0 ) and
- ( iNew < iLength - 2 ) ) then
- iDecimal := iNew
- else
- Raise EXbFormatError.Create(
- 'Bad decimal length: Not numeric field, or too long' );
- end; { TDBField.SetDecimal() }
-
- function TDBField.TypeWord : string;
- begin
- case cType of
- 'B' : Result := 'Binary (or FoxPro Double)';
- 'C' : Result := 'Character';
- 'D' : Result := 'Date';
- 'F' : Result := 'Floating point';
- 'G' : Result := 'General or OLE';
- 'I' : Result := 'smallint';
- 'L' : Result := 'Logical';
- 'M' : Result := 'Memo';
- 'N' : Result := 'Numeric';
- 'P' : Result := 'Picture';
- 'T' : Result := 'DateTime';
- 'V' : Result := 'Varifield';
- 'Y' : Result := 'Currency';
- else
- Result := 'Unknown';
- end; { case }
- end; { TDBField.TypeWord }
-
- function TDBField.IsMemo : boolean;
- begin
- Result := ( cType in [ 'B', 'G', 'M' ] );
- end; { TDBField.IsMemo }
-
- function TDBField.Header : DBFieldRec;
- begin
- with Result do begin
- FillChar( Result, SizeOf( Result ), 0 );
- StrPCopy( szName, FieldName );
- cFieldType := cType;
- if cType = 'C' then
- wCharLen := FieldLength
- else begin
- iLength := FieldLength;
- iDecimal := FieldDecimal;
- end; { not character type }
- end; { with Result }
- end; { TDBField.Header }
-
- constructor TDBField.Create( { Create the field entry }
- sFieldName : string; { Name of the field }
- cFieldType : char; { Character type code for the field }
- iFieldLength : smallint; { Length of the field }
- iFieldDecimal : smallint { Decimal precision for numeric fields }
- );
- begin
- inherited Create;
- try
- FieldName := sFieldName;
- FieldType := cFieldType;
- FieldLength := iFieldLength;
- FieldDecimal := iFieldDecimal;
- except
- on E : EXbFormatError do
- ShowMessage( E.Message );
- end; { try .. except }
- end; { TDBField.Create() }
-
- function TDBStruct.GetBlockSize : smallint;
- begin
- if iBlockSize = 0 then
- case TableType of
- xbDB3 : Result := 512;
- xbDB4 : Result := 1024;
- xbFPT : Result := 32;
- xbSMT : Result := 1;
- else Result := 0;
- end { case }
- else
- Result := iBlockSize;
- end; { TDBStruct.GetBlockSize }
-
- procedure TDBStruct.SetBlockSize( { Set the block size }
- iNew : smallint );
- var
- iLow,
- iHigh : smallint;
- begin
- case TableType of
- xbDB3 :
- begin
- iLow := 512;
- iHigh := 512;
- end;
- xbDB4 :
- begin
- iLow := 512;
- iHigh := 1024;
- end;
- else
- begin
- iLow := 1;
- iHigh := 32000;
- end; { else }
- end; { case }
- if ( iNew > 0 ) and ( iNew < 32000 ) then
- iBlockSize := iNew
- else
- Raise EXbFormatError.Create( 'Acceptable BlockSize range is ' +
- IntToStr( iLow ) + '..' + IntToStr( iHigh ) );
- end;
-
- constructor TDBStruct.Create;
- begin
- inherited Create;
- bEncrypt := False;
- iBlockSize := 0;
- end; { TDBStruct.Create }
-
- function TDBStruct.GetField( Index: smallint ): TDBField;
- begin
- Result := TDBField( inherited Get( Index - 1 ) ); { Convert to 0-based }
- end; { TDBStruct.GetField() }
-
- procedure TDBStruct.PutField( Index : smallint; oField : TDBField );
- begin
- inherited Put( Index - 1, @oField );
- end; { TDBStruct.PutField() }
-
- procedure TDBStruct.Free; { Free all objects created for Directory services }
- var
- iField : smallint;
- begin
- for iField := 1 to Count do
- Fields[ iField ].Free;
- inherited Free;
- end; { TDBStruct.Free }
-
- procedure TDBStruct.Eval( { Do something to every field entry }
- cbProc : xbBlockProc { Procedure "code block" type }
- );
- var
- iField : smallint;
- begin
- for iField := 1 to Count do
- with Fields[ iField ] do
- cbProc( [ FieldName, FieldType, FieldLength, FieldDecimal ] );
- end; { TDBStruct.Eval }
-
- function DBFileType( { DBF File Type }
- iSignature : byte { Signature byte }
- ) : string;
- begin
- case iSignature of
- _DBF_FOXBASE : Result := 'FoxBase, no memo';
- _DBF_NO_MEMO : Result := 'dBASE III+';
- _DBF_ENCRYPT : Result := 'Apollo encrypted, no memo';
- _DBF_VFP : Result := 'Visual FoxPro';
- _DBF_DB4_SQL : Result := 'dBASE IV SQL table, no memo';
- _DBF_DB4_SQLSYS : Result := 'dBASE IV SQL system file, no memo';
- _DBF_DBT_MEMO : Result := 'CA-Clipper/dBASE III+ .DBT memo';
- _DBF_DBT_ENCRYPT : Result := 'Apollo encrypted, no memo';
- _DBF_DB4_MEMO : Result := 'dBASE IV .DBT memo';
- _DBF_DB4_SQLMEMO : Result := 'dBASE IV SQL table, memo';
- _DBF_SMT_MEMO : Result := 'HiPer SIx with memo';
- _DBF_SMT_ENCRYPT : Result := 'HiPer SIx with memo, encrypted';
- _DBF_FPT_MEMO : Result := 'FoxPro .FPT memo';
- _DBF_FPT_ENCRYPT : Result := 'Apollo encrypted, FoxPro memo';
- _DBF_FOX_MEMO : Result := 'FoxBASE memo';
- else Result := 'Unrecognized DBF file type';
- end; { case }
- end; { DBFileType() }
-
- function TDBStruct.TableType : xbMemoType;
- begin
- sDriver := UpperCase( sDriver );
- Result := xbDB3;
- if ( Length( sDriver ) = 0 ) or ( sDriver = 'DEFAULT' )
- or ( sDriver = 'SIXNTX' ) or ( sDriver = 'DBFNTX' ) then
- Result := xbDB3 { Clipper DBF is encoded the same }
- else if ( sDriver = 'DBASE' ) or ( sDriver = 'DBFMDX' ) then
- Result := xbDB4
- else if ( sDriver = 'SIXCDX' ) or ( sDriver = 'SIXFOX' )
- or ( sDriver = 'DBFCDX' ) then
- Result := xbFPT
- else if ( sDriver = 'SIXNSX' ) or ( sDriver = 'DBFNSX' ) then
- Result := xbSMT;
- end; { TDBStruct.TableType() }
-
- function TDBStruct.Signature : byte;
- type
- xbMatrixType = array [ xbDB3..xbSMT, False..True ] of byte;
-
- const
- xbMatrix : xbMatrixType = (
- ( _DBF_DBT_MEMO, _DBF_DBT_ENCRYPT ),
- ( _DBF_DB4_MEMO, _DBF_DB4_MEMO ),
- ( _DBF_FPT_MEMO, _DBF_FPT_ENCRYPT ),
- ( _DBF_SMT_MEMO, _DBF_SMT_ENCRYPT ) );
-
- var
- xbDriver : xbMemoType;
-
- begin
- Result := _DBF_NO_MEMO;
- try
- xbDriver := TableType;
- if HasMemo then
- Result := xbMatrix[ xbDriver, bEncrypt ]
- else if bEncrypt then
- Result := _DBF_ENCRYPT;
- except
- Result := _DBF_NO_MEMO;
- end;
- end; { TDBStruct.Signature }
-
- function TDBStruct.HasMemo : boolean; { Is there a memo field in the DBF? }
- var
- iField : smallint;
-
- begin
- Result := False;
- for iField := 1 to Count do
- if Fields[ iField ].IsMemo then begin
- Result := True;
- break;
- end;
- end; { TDBStruct.HasMemo }
-
- function TDBStruct.DataOffset : smallint; { Position of first record in file }
- begin
- Result := SizeOf( DBFHeaderRec ) + Count * SizeOf( DBFieldRec ) + 1;
- end; { TDBStruct.DataOffset }
-
- function TDBStruct.RecordLength : smallint; { # of bytes per record }
- var
- iField : smallint;
- begin
- Result := 1;
- for iField := 1 to Count do
- Result := Result + Fields[ iField ].FieldLength;
- end; { TDBStruct.RecordLength }
-
- function TDBStruct.MakeMemoHeader( { Write a memo header structure to file }
- sFile : string; { Name of memo file }
- const Header; { Header structure to write }
- iSize : longint { Size of header structure }
- ) : boolean; { True if successful }
- var
- iPadSize,
- iHandle : smallint;
- cWipe : char;
- begin
- Result := False;
- try
- iHandle := FileCreate( sFile );
- if iHandle > -1 then begin
- Result := FileWrite( iHandle, Header, iSize ) = iSize;
- cWipe := #0;
- iPadSize := BlockSize;
- while ( iSize < iPadSize ) and ( Result ) do begin
- Result := FileWrite( iHandle, cWipe, 1 ) = 1;
- Inc( iSize, 1 );
- end; { while }
- end; { file created }
- if not Result then
- Raise EXbFormatError.Create( 'Could not create memo file ' + sFile );
- finally
- FileClose( iHandle );
- end; { try .. finally }
- end; { TDBStruct.MakeMemoHeader() }
-
- function TDBStruct.MakeDBT3( { Create dBASE III+/CA-Clipper memo file }
- sFile : string { Name of DBF file }
- ) : boolean;
- var
- recMemo : DBT3HeaderRec;
- iSize : smallint;
- begin
- try
- iSize := SizeOf( recMemo );
- FillChar( recMemo, iSize, 0 );
- recMemo.lBlocks := 1;
- Result := MakeMemoHeader( ChangeFileExt( sFile, '.DBT' ), recMemo,
- iSize );
- except
- Result := False;
- end;
- end; { TDBStruct.MakeDBT3() }
-
- function TDBStruct.MakeDBT4( { Create dBASE IV and up memo file }
- sFile : string { Name of DBF file }
- ) : boolean;
- var
- recMemo : DBT4HeaderRec;
- iSize : smallint;
- begin
- try
- iSize := SizeOf( recMemo );
- FillChar( recMemo, iSize, 0 );
- with recMemo do begin
- lNextBlock := 1; { Next free block to be used }
- lCurBlockSz := 0;
- StrPCopy( szDBFName, UpperCase( ExtractFileFirst( sFile ) ) );
- wVersion := _DBT4_VERSION;
- wBlockSize := BlockSize; { Block size being used, in bytes }
- bEncrypted := bEncrypt; { Is file encrypted? }
- end; { with RecMemo }
-
- Result := MakeMemoHeader( ChangeFileExt( sFile, '.DBT' ), recMemo,
- iSize );
- except
- Result := False;
- end;
- end; { TDBStruct.MakeDBT4() }
-
- function TDBStruct.MakeSMT( { Create a HiPer SIx memo file }
- sFile : string { Name of DBF file }
- ) : boolean;
- var
- recMemo : SMTHeaderRec;
- iSize : smallint;
- begin
- try
- iSize := SizeOf( recMemo );
- FillChar( recMemo, iSize, 0 );
- with recMemo do begin
- lBlockSize := BlockSize; { Block size being used, in bytes }
- if lBlockSize > 512 then
- lNextBlock := 1 { Next free block to be used }
- else
- lNextBlock := 512 div lBlockSize;
- end; { with recMemo }
- Result := MakeMemoHeader( ChangeFileExt( sFile, '.SMT' ), recMemo,
- iSize );
- except
- Result := False;
- end;
- end; { TDBStruct.MakeSMT() }
-
- function TDBStruct.MakeFPT( { Create a FoxPro memo file }
- sFile : string { Name of DBF file }
- ) : boolean;
- var
- recMemo : FPTHeaderRec;
- iSize : smallint;
- begin
- try
- iSize := SizeOf( recMemo );
- FillChar( recMemo, iSize, 0 );
- with recMemo do begin
- lBlockSize := BlockSize; { Block size being used, in bytes }
- if lBlockSize > 512 then
- lNextBlock := 1 { Next free block to be used }
- else
- lNextBlock := 512 div lBlockSize;
- lNextBlock := ReverseBytes( lNextBlock );
- lBlockSize := ReverseBytes( lBlockSize );
- end; { with recMemo }
- Result := MakeMemoHeader( ChangeFileExt( sFile, '.FPT' ), recMemo,
- iSize );
- except
- Result := False;
- end;
- end; { TDBStruct.MakeFPT() }
-
- function TDBStruct.MakeMemo( { Create memo file if necessary }
- sFile : string { DBF file name }
- ) : boolean; { True if successful }
- begin
- try
- case Signature of
- _DBF_DBT_MEMO : Result := MakeDBT3( sFile );
- _DBF_DB4_MEMO : Result := MakeDBT4( sFile );
- _DBF_SMT_MEMO,
- _DBF_SMT_ENCRYPT : Result := MakeSMT( sFile );
- _DBF_FPT_MEMO,
- _DBF_FPT_ENCRYPT : Result := MakeFPT( sFile );
- else Result := True;
- end; { case }
- except
- Result := False;
- end; { try .. except }
- end; { TDBStruct.MakeMemo() }
-
- function TDBStruct.Make( { Create the DBF file }
- sFile : string { DBF file name }
- ) : boolean; { True if successful }
- const
- DBF_END_FIELDS : array [ 0..1 ] of char = #13+#26;
-
- var
- recDBF : DBFHeaderRec;
- recField : DBFieldRec;
- wYear,
- wMonth,
- wDay : word;
- iField,
- iHandle : smallint;
- dNow : TDateTime;
-
- begin
- Result := False;
- try
- iHandle := fCreate( sFile, FC_NORMAL );
- if iHandle > -1 then begin
- dNow := Date;
- DecodeDate( dNow, wYear, wMonth, wDay );
- FillChar( recDBF, SizeOf( recDBF ), 0 );
- with recDBF do begin
- iSignature := Signature;
- iYear := wYear - 1900;
- iMonth := wMonth;
- iDay := wDay;
- lRecords := 0;
- wDataOffset := DataOffset;
- wRecLen := RecordLength;
- iLanguage := 27;
- end; { with recDBF }
- if FileWrite( iHandle, recDBF, SizeOf( recDBF ) ) = SizeOf( recDBF )
- then begin
- for iField := 1 to Count do begin
- recField := Fields[ iField ].Header;
- FileWrite( iHandle, recField, SizeOf( recField ) );
- end;
- FileWrite( iHandle, DBF_END_FIELDS, 2 );
- MakeMemo( sFile );
- Result := True;
- end
- else
- Raise EXbFormatError.Create( 'Could not create header for ' + sFile );
- end; { File created }
- finally
- FileClose( iHandle );
- end;
- end; { TDBStruct.Make() }
-
- function DBFieldCount( { # of fields in data file }
- recDBF : DBFHeaderRec { Database file header }
- ) : smallint;
- begin
- Result := ( recDBF.wDataOffset - SizeOf( DBFHeaderRec ) - 1 )
- div SizeOf( DBFieldRec ); { Calc the # of fields }
- end; { DBFieldCount() }
-
- function DBStructRead( { Read the structure from a DBF file }
- sFile : string
- ) : TDBStruct;
- var
- recHeader : DBFHeaderRec;
- recField : DBFieldRec;
- iField,
- iHandle : smallint;
- oField : TDBField;
-
- begin
- Result := nil;
- try
-
- iHandle := FileOpen( sFile, FO_READ );
- if iHandle > -1 then
- begin
- Result := TDBStruct.Create;
- FileRead( iHandle, recHeader, Sizeof( recHeader ) );
- Result.Capacity := DBFieldCount( recHeader );
- for iField := 0 to Result.Capacity - 1 do begin
- FileRead( iHandle, recField, sizeof( recField ) );
- with recField do
- if cFieldType = 'C' then
- oField := TDBField.Create( StrPas( szName ), cFieldType,
- wCharLen, 0 )
- else
- oField := TDBField.Create( StrPas( szName ), cFieldType,
- iLength, iDecimal );
- Result.Add( oField );
- end; { for iField }
- end; { File Opened successfully }
-
- finally
- FileClose( iHandle );
- end; { try .. finally }
- end; { DBStructRead() }
-
- function dbCreateStruct( { Convert array of const to DBStruct }
- aStruct : array of const { Field structure information:
- 4 array elements per field:
- 1. Field name (string)
- 2. Field type (char)
- 3. Field length (smallint)
- 4. Field decimal (smallint) }
- ) : TDBStruct; { Use TDBStruct.Free when done! }
- var
- iField,
- iFields : smallint;
- begin
- iFields := High( aStruct ) div 4;
- try
- Result := TDBStruct.Create;
- Result.Capacity := iFields;
- for iField := 0 to iFields do
- Result.Add( TDBField.Create(
- {$IFDEF WIN32}
- aStruct[ iField * 4 ].VPChar,
- {$ELSE}
- aStruct[ iField * 4 ].VString^,
- {$ENDIF}
- aStruct[ iField * 4 + 1 ].VChar,
- aStruct[ iField * 4 + 2 ].VInteger,
- aStruct[ iField * 4 + 3 ].VInteger ) );
- except
- on E : EXbFormatError do
- ShowMessage( E.Message );
- end; { try .. except }
- end; { dbCreateStruct() }
-
- {$IFNDEF XP_NO_NATIVE_DBCREATE}
- function dbCreate( { Create a data file }
- sDataFile : string; { Name of data file to create }
- oStruct : TDBStruct; { Database structure object }
- sDriver : string; { Name of data driver to use for creation }
- bEncrypt : boolean { Encrypt the file? }
- ) : boolean;
- begin
- try
- if Length( sDriver ) > 0 then
- oStruct.sDriver := sDriver;
- oStruct.bEncrypt := bEncrypt;
- Result := oStruct.Make( sDataFile );
- except
- Result := False;
- end; { try .. except }
- end; { dbCreate() }
- {$ENDIF}
-
- procedure ShowDBF( { Show structure of an DBF file }
- sFile : string ); { Name of DBF file }
- var
- recHeader : DBFHeaderRec;
- begin
- if dbHeaderRead( sFile, recHeader, SizeOf( recHeader ) ) then
- with recHeader do begin
- WriteLn( 'iSignature :', iSignature,
- ' (', DBFileType( iSignature ), ')' );
- WriteLn( 'iYear :', iYear );
- WriteLn( 'iMonth :', iMonth );
- WriteLn( 'iDay :', iDay );
- WriteLn( 'lRecords :', lRecords );
- WriteLn( 'wDataOffset :', wDataOffset );
- WriteLn( 'wRecLen :', wRecLen );
- WriteLn( 'bIncomplete :', bIncomplete );
- WriteLn( 'bEncrypted :', bEncrypted );
- WriteLn( 'sMultiuser :', sMultiuser );
- WriteLn( 'iFlags :', iFlags );
- WriteLn( 'iLanguage :', iLanguage );
- end; { with }
-
- end; { ShowDBF() }
-
- procedure ShowDBT3( { Show structure of a DBT3 file }
- sFile : string ); { Name of DBT file }
- var
- recHeader : DBT3HeaderRec;
- begin
- if dbHeaderRead( sFile, recHeader, SizeOf( recHeader ) ) then
- WriteLn( 'lBlocks :', recHeader.lBlocks );
- end; { ShowDBT3() }
-
- procedure ShowDBT4( { Show structure of a DBT4 file }
- sFile : string ); { Name of DBT file }
- var
- recHeader : DBT4HeaderRec;
- begin
- if dbHeaderRead( sFile, recHeader, SizeOf( recHeader ) ) then
- with recHeader do begin
- WriteLn( 'lNextBlock :', lNextBlock );
- WriteLn( 'lCurBlockSz :', lCurBlockSz );
- WriteLn( 'szDBFName :', szDBFName );
- WriteLn( 'wVersion :', wVersion );
- WriteLn( 'wBlockSize :', wBlockSize );
- WriteLn( 'bEncrypted :', bEncrypted );
- end; { with }
- end; { ShowDBT4() }
-
- procedure ShowSMT( { Show structure of an SMT file }
- sFile : string ); { Name of SMT file }
- var
- recHeader : SMTHeaderRec;
- begin
- if dbHeaderRead( sFile, recHeader, SizeOf( recHeader ) ) then
- with recHeader do begin
- WriteLn( 'lNextBlock :', lNextBlock );
- WriteLn( 'lBlockSize :', lBlockSize );
- end; { with }
- end; { ShowSMT() }
-
- procedure ShowFPT( { Show structure of an FPT file }
- sFile : string ); { Name of FPT file }
- var
- recHeader : FPTHeaderRec;
- begin
- if dbHeaderRead( sFile, recHeader, SizeOf( recHeader ) ) then
- with recHeader do begin
- WriteLn( 'lNextBlock :', ReverseBytes( lNextBlock ) );
- WriteLn( 'lBlockSize :', ReverseBytes( lBlockSize ) );
- end; { with }
- end; { ShowFPT() }
-
- end.
-